package com.guardian.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

/**
 * io工具
 * @author: huwei
 * @date: 2019/10/12 10:43
 * @version: 1.0.0
 */
public class IoUtils {


    public static String unblockReadStream(InputStream is ,long timeout , TimeUnit unit) throws IOException, InterruptedException {
        return unblockReadStream(new BufferedReader(new InputStreamReader(is)) ,timeout ,unit);
    }


    public static String unblockReadStream(BufferedReader reader , long timeout , TimeUnit unit) throws IOException, InterruptedException {
        StringBuilder data = new StringBuilder();
        AtomicBoolean isException = new AtomicBoolean(false);
        AtomicBoolean isBlock = new AtomicBoolean(false);
        AtomicBoolean isOver = new AtomicBoolean(false);
        //读取流休眠的时间
        AtomicLong streamBlockTime = new AtomicLong(0);

        Thread t = new Thread(()->{
            try {
                String line;
                while ( setAndGet(isBlock ,true) && (line = reader.readLine()) != null) {
                    isBlock.set(false);
                    streamBlockTime.set(0);
                    data.append(line).append(System.lineSeparator());
                }
                isOver.set(true);
            }catch (IOException e){
                isException.set(true);
            }
        });
        t.start();

        //默认最低timeout时间，防止正常停顿时间，被timeout处理
        long rem = unit.toMillis(timeout) <= 1000 ? 2000 : unit.toMillis(timeout);

        do {
            if(isOver.get()){
                break;
            }
            if(isException.get()){
                throw new IOException("read byte fail");
            }
            if(isBlock.get()) {
                if (streamBlockTime.get() < rem) {
                    Thread.sleep(50);
                    long tt = streamBlockTime.addAndGet(50);
                }else{
                    //timeout 中断线程 ,退出循环
                    t.interrupt();
                    break;
                }
            }else{
                Thread.sleep(100);
            }
        } while (true);

        return data.toString();
    }

    private static boolean setAndGet(AtomicBoolean atomicBoolean ,boolean setValue){
        atomicBoolean.set(setValue);
        return atomicBoolean.get();
    }
}
